package org.mtdownload.progressview;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.geom.Arc2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.List;

import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;

import org.mtdownload.download.DownloadManager;
import org.mtdownload.download.DownloadTask;
import org.mtdownload.download.DownloadTaskPropertiesChanged;
import org.mtdownload.download.DownloadThread;
import org.mtdownload.utils.CircularEnumeration;
import org.mtdownload.utils.PreferencesManager;

public class MTDownloadProgressView extends JPanel{

	private static final long serialVersionUID = 3977017353403839796L;
	
	private static final int BLOCK_WIDTH=10;
	private static final int BLOCK_HEIGHT=10;
	private static final int PROGRESSBAR_MAX_HEIGHT=80;
	
	private int blockBytes=PreferencesManager.getBlockBytes();	
	private DownloadTask curentlySelectedTask=null;	
	private Dimension size=null;
	
	private JPanel progressTypeChooserPanel=new JPanel(new FlowLayout(FlowLayout.LEADING));
	private JComboBox progressTypeCombo=new JComboBox();
	
	private JPanel progressCanvas=null;
	private List<Color> colorsList=null;
	private CircularEnumeration<Color> colorsEnumeration=new CircularEnumeration<Color>(); 
		
	public MTDownloadProgressView(){
		init();
	}
	
	private void init(){
		DownloadManager.addDownloadTaskPropertiesChangedListener(new DownloadTaskPropertiesChanged(){
			public void propertiesChanged(DownloadTask task) {
				if(task.equals(curentlySelectedTask)){
					progressCanvas.repaint();
				}
			}
		});
		progressTypeCombo.addItem(PreferencesManager.PROGRESS_TYPE_BAR);
		progressTypeCombo.addItem(PreferencesManager.PROGRESS_TYPE_BAR_COLORS);
		progressTypeCombo.addItem(PreferencesManager.PROGRESS_TYPE_PIE);
		progressTypeCombo.addItem(PreferencesManager.PROGRESS_TYPE_PIE_COLORS);		
		progressTypeCombo.addItem(PreferencesManager.PROGRESS_TYPE_NONE);
		progressTypeCombo.setSelectedItem(PreferencesManager.getProgressType());
		progressTypeChooserPanel.add(new JLabel("Choose display type:"));
		progressTypeChooserPanel.add(progressTypeCombo);
		progressTypeCombo.addItemListener(new ItemListener(){
			public void itemStateChanged(ItemEvent e) {
				PreferencesManager.setProgressType((String)progressTypeCombo.getSelectedItem());
				progressCanvas.repaint();
			}			
		});
		progressCanvas=new JPanel(){
			private static final long serialVersionUID = 4050760503079219248L;
			public void paintComponent(Graphics g){
				super.paintComponent(g);	
				if(curentlySelectedTask==null||curentlySelectedTask.getFileLength()<0)return;
				if(!curentlySelectedTask.isAllThreadsSpawned()) return;
				Graphics2D g2=(Graphics2D)g;
				String progressType=(String)progressTypeCombo.getSelectedItem();
				Dimension size=getSize();
				colorsList=PreferencesManager.getProgressColorsList();
				colorsEnumeration.setList(colorsList);
				if(progressType.equals(PreferencesManager.PROGRESS_TYPE_NONE)){
					return;
				}				
				if(progressType.equals(PreferencesManager.PROGRESS_TYPE_BAR) || progressType.equals(PreferencesManager.PROGRESS_TYPE_BAR_COLORS)){
					paintProgressBar(g2,size);
				}
				if(progressType.equals(PreferencesManager.PROGRESS_TYPE_PIE) || progressType.equals(PreferencesManager.PROGRESS_TYPE_PIE_COLORS)){
					paintProgressPie(g2,size);
				}				
			}
		};
		setLayout(new BorderLayout());
		add(progressTypeChooserPanel,BorderLayout.NORTH);
		add(progressCanvas,BorderLayout.CENTER);
	}
	
	private void paintProgressBar(Graphics2D g,Dimension size){
		if(size.height>PROGRESSBAR_MAX_HEIGHT){
			size.height=PROGRESSBAR_MAX_HEIGHT;
		}
		Rectangle bounds=new Rectangle(10,10,size.width-20,size.height-5);		
		g.setPaint(PreferencesManager.getProgressBackgroundColor());		
		g.fill(bounds);
		long fileLength=curentlySelectedTask.getFileLength();
		long bytesPerPixel=fileLength/bounds.width;					
		if(curentlySelectedTask.getMasterThread().getThreads()!=null){
			for(DownloadThread thread:curentlySelectedTask.getMasterThread().getThreads()){
				paintBarThreadProgress(g,thread,bounds,bytesPerPixel);
			}
		}else{
			paintBarThreadProgress(g,curentlySelectedTask.getMasterThread(),bounds,bytesPerPixel);
		}
		String percent=curentlySelectedTask.getHumanFriendlyPercent();
		Rectangle2D percentBounds=g.getFontMetrics().getStringBounds(percent,g);
		g.setPaint(PreferencesManager.getProgressBackgroundColor());
		percentBounds.setRect(bounds.width/2,bounds.height/2,percentBounds.getWidth(),percentBounds.getHeight());
		g.fill(percentBounds);
		g.setPaint(PreferencesManager.getProgressTextColor());
		g.drawString(curentlySelectedTask.getHumanFriendlyPercent(),bounds.width/2,bounds.height/2+bounds.y);
	}
	
	private void paintBarThreadProgress(Graphics2D g,DownloadThread thread,Rectangle bounds,long bytesPerPixel){
		if(bytesPerPixel==0)return;//to avoid division by 0
		long startPosition=thread.getStartingPosition();
		long currentPosition=thread.getCurrentPosition();
		long completed=currentPosition-startPosition;		
		int startPixel=(int)(startPosition/bytesPerPixel)+bounds.x;
		int endPixel=(int)(currentPosition/bytesPerPixel)+bounds.x;
		int widthPixel=(int)(completed/bytesPerPixel)+1;//+1 is here because sometimes a white line 
		//appears in the progress bar, even though the drawing is done to the end, and the thread completed it's part
		//it looks like is not finished. 1 extra pixel shoudn't be noticeable for the user
		//it's a small lie :)) a <bytesPerPixel> lie :)
		String progressType=(String)progressTypeCombo.getSelectedItem();
		if(progressType.equals(PreferencesManager.PROGRESS_TYPE_BAR)){
			g.setPaint(PreferencesManager.getProgressSingleColor());
		}
		if(progressType.equals(PreferencesManager.PROGRESS_TYPE_BAR_COLORS)){
			g.setPaint(colorsEnumeration.nextElement());
		}		
		g.fillRect(startPixel,bounds.y,widthPixel,bounds.height);
		//g.setPaint(Color.RED);
		//g.drawLine(endPixel,bounds.y,endPixel,bounds.height-1+bounds.y);
	}
	

	private void paintProgressPie(Graphics2D g,Dimension size){
		Rectangle bounds=new Rectangle(10,10,size.width-20,size.height-15);
        g.setPaint(PreferencesManager.getProgressBackgroundColor());	
		Ellipse2D circle=new Ellipse2D.Double((bounds.width-bounds.height)/2, bounds.y, bounds.height, bounds.height);
		g.fill(circle);		
		long fileLength=curentlySelectedTask.getFileLength();
		long bytesPerDegree=fileLength/360;					
		if(curentlySelectedTask.getMasterThread().getThreads()!=null){
			for(DownloadThread thread:curentlySelectedTask.getMasterThread().getThreads()){
				paintPieThreadProgress(g,thread,circle.getBounds(),circle,bytesPerDegree);
			}
		}else{
			paintPieThreadProgress(g,curentlySelectedTask.getMasterThread(),circle.getBounds(),circle,bytesPerDegree);
		}
		String percent=curentlySelectedTask.getHumanFriendlyPercent();
		Rectangle2D percentBounds=g.getFontMetrics().getStringBounds(percent,g);
		g.setPaint(PreferencesManager.getProgressBackgroundColor());
		percentBounds.setRect(bounds.width/2-(int)percentBounds.getWidth()/2,bounds.height/2,percentBounds.getWidth(),percentBounds.getHeight());
		g.fill(percentBounds);
		g.setPaint(PreferencesManager.getProgressTextColor());
		g.drawString(curentlySelectedTask.getHumanFriendlyPercent(),bounds.width/2-(int)percentBounds.getWidth()/2,bounds.height/2+bounds.y);		
	}
	
	private void paintPieThreadProgress(Graphics2D g,DownloadThread thread,Rectangle bounds,Ellipse2D circle,long bytesPerDegree){
		if(bytesPerDegree<=0)return;
		long startPosition=thread.getStartingPosition();
		long currentPosition=thread.getCurrentPosition();				
		int startDegree=(int)(startPosition/bytesPerDegree);
		int endDegree=(int)(currentPosition/bytesPerDegree);
		String progressType=(String)progressTypeCombo.getSelectedItem();
		if(progressType.equals(PreferencesManager.PROGRESS_TYPE_PIE)){			
			g.setPaint(PreferencesManager.getProgressSingleColor());
		}
		if(progressType.equals(PreferencesManager.PROGRESS_TYPE_PIE_COLORS)){
			g.setPaint(colorsEnumeration.nextElement());
		}						
        g.fill(new Arc2D.Double(bounds,startDegree,(endDegree-startDegree+1), Arc2D.PIE));
		//TODO Because of calculations errors (rounding errors i believe) drawing the lines doesn't work 
		// as expected
		/*g.setPaint(Color.RED);
		int radius=bounds.height/2;
		double angle = Math.toRadians(endDegree);		
		int x1=(int)(radius*Math.cos(angle)+circle.getCenterX());
		int y1=(int)(radius*Math.sin(angle)+circle.getCenterY());
		g.drawLine((int)circle.getCenterX(),(int)circle.getCenterY(),x1,y1);*/
	}
	

	/**
	 * @return Returns the curentlySelectedTask.
	 */
	public DownloadTask getCurentlySelectedTask() {
		return curentlySelectedTask;
	}
	
	/**
	 * @param curentlySelectedTask The curentlySelectedTask to set.
	 */
	public void setCurentlySelectedTask(DownloadTask curentlySelectedTask) {
		this.curentlySelectedTask = curentlySelectedTask;		
		if(curentlySelectedTask !=null&& curentlySelectedTask.getFileLength()>0){
			progressCanvas.repaint();
		}

	}	
}
